package io.terminus.lego.shinda.web.security.email.provider

import io.terminus.lego.shinda.service.service.UserService
import io.terminus.lego.shinda.web.cache.RedisCacheManager
import io.terminus.lego.shinda.web.cache.RedisKeyConstant
import io.terminus.lego.shinda.web.security.email.exception.EmailAuthenticationException
import io.terminus.lego.shinda.web.security.email.token.EmailLoginAuthenticationToken
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.authentication.AuthenticationProvider
import org.springframework.security.core.Authentication
import org.springframework.stereotype.Component

/**
 * @author wangmeng
 * @date 2018/4/20
 */
@Component
class EmailAuthenticationProvider @Autowired constructor(val userService: UserService, val redisCacheManager: RedisCacheManager) : AuthenticationProvider {
    private val retryLimit = 5

    override fun authenticate(authentication: Authentication): Authentication {
        authentication is EmailLoginAuthenticationToken
        //关键信息
        val email = authentication.principal.toString()
        val code = authentication.credentials.toString()
        val emailLoginRetryKey = RedisKeyConstant.getEmailLoginRetryKey(email)
        val emailLoginCodeKey = RedisKeyConstant.getEmaiLoginCodelKey(email)
        //校验验证码
        val value = redisCacheManager.getValue(emailLoginCodeKey)
                ?: throw EmailAuthenticationException("验证码无效")
        if (code == value) {
            var user = userService.findUserByEmail(authentication.principal.toString())
            //没有用户则自动创建
            if (user == null) {
                user = userService.createByEmail(email)
            }
            //username将成为为authentication.name
            val authenticationResult = EmailLoginAuthenticationToken(user.username!!, code, emptyList())
            authenticationResult.details = user
            redisCacheManager.remove(emailLoginCodeKey)
            redisCacheManager.remove(emailLoginRetryKey)
            return authenticationResult
        }
        //验证码次数校验、超出次数清楚缓存数据
        val retry = (redisCacheManager.getValue(emailLoginRetryKey) as Int) + 1
        if (retry >= retryLimit) {
            redisCacheManager.remove(emailLoginCodeKey)
        } else {
            redisCacheManager.setValue(emailLoginRetryKey, retry)
        }
        throw EmailAuthenticationException("验证码错误")
    }

    override fun supports(authentication: Class<*>?): Boolean {
        return authentication == EmailLoginAuthenticationToken::class.java
    }


}